Skip to content

perf(h1): reuse one pipe per connection for spliced bodies - #154

Merged
lexoliu merged 3 commits into
mainfrom
perf/142-pipe-reuse
Nov 11, 2026
Merged

lexoliu merged 3 commits into
mainfrom
perf/142-pipe-reuse

Conversation

@lexoliu

@lexoliu lexoliu commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator

The h1 server and client writers now poll the body they send with a PipeOffer. They only do this when the writer can splice. The offer carries the pipe the connection drained last, and Outbox keeps it between messages. The client's Outbox now lives on Connection. A forwarded body therefore uses one pipe per connection instead of a pipe2 and two closes per frame.

IncomingBody used to strand the offer and its pipe at the end of every body. It now takes back an unanswered demand when the body ends, and try_splice returns the empty pipe to the offer when it finds EOF. h3 never offers, so it gets plain data frames. Before, it read back a pipe a forwarder had made.

Body::poll_frame_offering now takes Option<&mut PipeOffer>, where None means poll_next. A forwarder passes its consumer's offer straight through instead of matching on it.

New splice tests run on compio and tokio. They count pipes by inode in /proc/self/fd and check that two keep-alive requests echoed through a pass-through forwarder share one pipe over more than four splices, and that a client reuses its drained pipe. The tests fail with the reattach removed. The kTLS splice-out path needs CI.

Closes #142

A writer whose socket can splice now polls the body it sends with a PipeOffer carrying the pipe its last pipe frame left, and the connection keeps that pipe between messages. A received body hands the offer back with its end, including one queued behind the last frame without a demand, and a splice that finds the end of the stream returns its empty pipe. A body forwarded from one connection to another therefore costs one pipe per connection instead of a pipe2 and two closes per frame, and a forwarder between them no longer has to offer on the writer's behalf.

Closes #142
A forwarder passes its consumer's offer, or its absence, straight through
instead of matching on it to choose poll_next.
@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 96.92308% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
h1/src/body.rs 92.00% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Reuse pipes across body frames instead of creating one per frame

2 participants